﻿namespace Yaaf.WP7.NativeAccess.Registry.Internals.HTC.COM_NativeAccess
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Yaaf.WP7.NativeAccess.ComWrapper.HTC.COM_NativeAccess;

    internal class RegistryKey : IDisposable
    {
        private static readonly string[] rootKeys = new string[] { "HKEY_CLASSES_ROOT", "HKEY_CURRENT_USER", "HKEY_LOCAL_MACHINE", "HKEY_USERS" };
        internal static readonly UIntPtr ClassesRoot = new UIntPtr(0x80000000);
        internal static readonly UIntPtr CurrentUser = new UIntPtr(0x80000001);
        internal static readonly UIntPtr LocalMachine = new UIntPtr(0x80000002);
        internal static readonly UIntPtr Users = new UIntPtr(0x80000003);
        private static readonly UIntPtr[] rootPtrs = new UIntPtr[] { ClassesRoot, CurrentUser, LocalMachine, Users };

        private UIntPtr handle;
        private string name;
        private bool isWriteable;
        private bool isSystemKey;

        private bool isRoot = false;

        public static RegistryKey Root = new RegistryKey();



        private RegistryKey(UIntPtr handle, string name, bool writeable, bool isSystemKey, RegistryKey parent)
        {
            Parent = parent;
            isRoot = false;
            this.handle = handle;
            this.name = name;
            this.isWriteable = writeable;
            this.isSystemKey = isSystemKey;
        }

        private RegistryKey()
        {
            isRoot = true;
        }

        internal static RegistryKey GetKey(UIntPtr handle)
        {
            int index = ((int) ((uint) handle)) & 0xfffffff;
            return new RegistryKey(handle, rootKeys[index], true, true, Root);
        }

        public void Close()
        {
            this.Dispose();
        }

        public void Dispose()
        {
            if (isRoot)
            {
                return;
            }
            if ((this.handle != UIntPtr.Zero) && !this.isSystemKey)
            {
                Registry.nativeRegistry.Close(this.handle);
                this.handle = UIntPtr.Zero;
            }
        }

        public uint GetDwordValue()
        {
           this.CheckRoot();
            return this.GetDwordValue(string.Empty, 0);
        }

        public uint GetDwordValue(string valueName)
        {
            this.CheckRoot();
            return this.GetDwordValue(valueName, 0);
        }

        public uint GetDwordValue(string valueName, uint defaultValue)
        {
            CheckRoot();
            uint num;
             try
            {
                if (Registry.nativeRegistry.GetDwordValue(this.handle, valueName, out num) == 0)
                {
                    return num;
                }
            }
             catch (OutOfMemoryException)
             {
                 // do not know why this is happening sometimes
             }
            return defaultValue;
        }

        private void CheckRoot()
        {
            if (this.isRoot)
            {
                throw new NotImplementedException();
            }
        }

        public int GetIntegerValue()
        {
            CheckRoot();
            return this.GetIntegerValue(string.Empty, 0);
        }

        public int GetIntegerValue(string valueName)
        {
            CheckRoot();
            return this.GetIntegerValue(valueName, 0);
        }

        public int GetIntegerValue(string valueName, int defaultValue)
        {
            CheckRoot();
            uint num;
             try
            {
                if (Registry.nativeRegistry.GetDwordValue(this.handle, valueName, out num) == 0)
                {
                    return (int) num;
                }
            }
            catch (OutOfMemoryException)
            {
                // do not know why this is happening sometimes
            }
            return defaultValue;
        }

        public string GetStringValue()
        {
            CheckRoot();
            return this.GetStringValue(string.Empty, null);
        }

        public string GetStringValue(string valueName)
        {
            CheckRoot();
            return this.GetStringValue(valueName, null);
        }

        public string GetStringValue(string valueName, string defaultValue)
        {
            CheckRoot();
            string str;
            try
            {
                if (Registry.nativeRegistry.GetStringValue(this.handle, valueName, out str) == 0)
                {
                    return str;
                }
            }
            catch (OutOfMemoryException)
            {
                // do not know why this is happening sometimes
            }
            
            return defaultValue;
        }

        public uint GetValueSize(string valueName)
        {
            CheckRoot();
            uint num;
             try
            {
                if (Registry.nativeRegistry.GetValueSize(this.handle, valueName, out num) == 0)
                {
                    return num;
                }
            }
             catch (OutOfMemoryException)
             {
                 // do not know why this is happening sometimes
             }
            return 0;
        }

        public RegistryValueType GetValueType(string valueName)
        {
            CheckRoot();
            uint num; 
            try
            {
                if (Registry.nativeRegistry.GetValueType(this.handle, valueName, out num) == 0)
                {
                    return (RegistryValueType) num;
                }
            }
            catch (OutOfMemoryException)
            {
                // do not know why this is happening sometimes
            }
            return RegistryValueType.None;
        }

        public RegistryKey OpenSubKey(string keyName)
        {
            CheckRoot();
            
                return this.OpenSubKey(keyName, false);
            
            

            return null;
        }

        public RegistryKey OpenSubKey(string keyName, bool writable)
        {
            CheckRoot();
            UIntPtr ptr = UIntPtr.Zero;
            if (this.handle == UIntPtr.Zero)
            {
                return null;
            }
            try
            {
                var errorCode = Registry.nativeRegistry.OpenSubKey(this.handle, keyName, out ptr);
                if (errorCode != 0)
                {
                    Console.WriteLine("Error while opening key: " + errorCode);
                    ptr = UIntPtr.Zero;
                }
            }
            catch (OutOfMemoryException)
            {
                // do not know why this is happening sometimes
                ptr = UIntPtr.Zero;
            }

            if (ptr == UIntPtr.Zero)
            {
                return null;
            }

            return new RegistryKey(ptr, string.Format(@"{0}\{1}", this.name, keyName), writable, false, this);
        }

        //public IEnumerable<RegistryKey> SubKeys
        //{
        //    get
        //    {
        //        if (isRoot)
        //        {
        //            var list = new List<RegistryKey>();
        //            for (int i = 0; i < rootPtrs.Length; i++)
        //            {
        //                var ptr = rootPtrs[i];
        //                list.Add(GetKey(ptr));
        //            }
        //            return list;
        //        }

        //        return RegistryAccess.GetSubKeyNames(this.Name).Select(OpenSubKey);
        //    }
        //}

        //public IEnumerable<string> ValueNames
        //{
        //    get
        //    {
        //        if (isRoot)
        //        {
        //            return new string[0];
        //        }
        //        return RegistryAccess.GetSubValues(this.Name);
        //    }
        //}

        public bool IsSystemKey
        {
            get
            {
                return this.isSystemKey;
            }
        }

        public bool IsWritable
        {
            get
            {
                return this.isWriteable;
            }
        }

        public string Name
        {
            get
            {
                return this.name;
            }
        }

        public RegistryKey Parent { get; private set; }
    }
}

